package com.gitee.mp.core.interceptor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import com.gitee.mp.core.exception.NoneMatchException;
import com.gitee.mp.core.mapper.MilvusMapper;
import com.gitee.mp.domain.definition.FieldDefinition;
import com.gitee.mp.extend.MapperInterceptor;
import com.gitee.mp.infra.utils.CollectionNameUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author hongda.li
 */
public abstract class AbstractMapperInterceptor implements MapperInterceptor {

    @Override
    public int order() {
        return 0;
    }

    @Override
    public boolean supported(Class<?> mapper) {
        return MilvusMapper.class.isAssignableFrom(mapper);
    }

    /**
     * 获取集合名称
     *
     * @param context 上下文
     * @return 集合名称
     */
    protected String getCollectionName(InterceptorContext context) {
        return CollectionNameUtils.fetchCollectionName(context.getDefinition());
    }

    /**
     * 将 Bean 转为 Map
     *
     * @param bean 原始 Bean
     * @return 转换结果
     */
    protected Map<String, Object> beanToMap(Object bean) {
        return BeanUtil.beanToMap(bean, new LinkedHashMap<>(), false, true);
    }

    /**
     * 将实体字段名称转为集合字段名称
     *
     * @param context 上下文
     * @param dataMap 原始数据
     * @return 转换后的数据
     */
    protected Map<String, Object> transformParams(InterceptorContext context, Map<String, Object> dataMap) {
        Map<String, String> mapping = context.getDefinition()
                .getFieldDefinitionList()
                .stream()
                .collect(Collectors.toMap(FieldDefinition::getFrom, FieldDefinition::getFieldName));

        Map<String, Object> newDataMap = MapUtil.newHashMap(dataMap.size(), true);
        mapping.forEach((from, target) -> newDataMap.put(target, dataMap.get(from)));

        return newDataMap;
    }

    /**
     * 获取主键列表
     *
     * @param context  上下文
     * @param dataList 原始数据
     * @return 原始数据对应的主键列表
     */
    protected List<Object> getPrimaryKeyList(InterceptorContext context, List<?> dataList) {
        String primaryKeyName = context.getDefinition()
                .getFieldDefinitionList()
                .stream()
                .filter(FieldDefinition::isPrimary)
                .findFirst()
                .map(FieldDefinition::getFrom)
                .orElseThrow(() -> new NoneMatchException("None match for the primary key of entity : {}", context.getEntity().getName()));

        return dataList.stream()
                .map(this::beanToMap)
                .map(map -> map.get(primaryKeyName))
                .filter(Objects::nonNull)
                .toList();
    }
}
